package com.qiang.util;


import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;

public class DateUtil implements Serializable {

	private static Logger logger = LoggerFactory.getLogger(DateUtil.class);
	public static final String yyyyMMdd = "yyyy-MM-dd";
	public static final String yyyyMMddHHmm = "yyyy-MM-dd HH:mm";
    private static final DateTimeFormatter YYYYMMDDHHMMSS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter YYYYMMDD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter ymd = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter hhmmss = DateTimeFormatter.ofPattern("HH:mm:ss");
    public static final DateTimeFormatter HHmmsdf = DateTimeFormatter.ofPattern("HH:mm");

	/**
	 * 获取当前时间下N个月
	 * @param dateStr
	 * @param month
	 * @return
	 */
	public static String getTimeForJs(String dateStr,Integer month){
		//获取当前时间
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyyMMdd);
		Date date = str2Date(dateStr,simpleDateFormat);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		//当前时间前去一个月，即一个月前的时间
		calendar.add(Calendar.MONTH, month);
		Date nowTime = getNextDayTime(calendar.getTime(),-1);
		return  dateToStr(nowTime);
	}

	public static Date str2Date(String str,SimpleDateFormat sdf) {
		if (StringUtils.isBlank(str)){
			return null;
		}else{
			try {
				return sdf.parse(str);
			} catch (ParseException e) {
				logger.error("str2Date={}",e);
			}
		}
		return null;
	}

	/**
	 * 获取当前时间的下一天
	 *
	 * @param date
	 * @return
	 */
	public static String getNextDay(Date date) {
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_YEAR, 1);
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyyMMdd);
		return simpleDateFormat.format(calendar.getTime());
	}

	/**
	 * 时间格式化（到日期）
	 *
	 * @param date
	 * @return
	 */
	public static String formatDate(Date date) {
        String newDate = dateToStringYYYYMMDDByJDK8(date);
        return newDate;
	}

	/**
	 * 时间格式化（到秒）
	 * @param date
	 * @return
	 */
	public static String formatTime(Date date) {
        String newDate = dateToStringYYYYMMDDHHMMSSByJDK8(date);
		return newDate;
	}

	/**
	 * 时间格式化（到秒）
	 *
	 * @param ticks
	 *            时间刻度
	 * @return
	 */
	public static Date formatTime(Long ticks) {
		Instant instant = Instant.ofEpochMilli(ticks);
		ZoneId zone = ZoneId.systemDefault();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
		Date date = localDateTime2Date(localDateTime);
		return date;
	}

	public static Date stringDateMin(String s) {
		Date date = null;
		try {
			SimpleDateFormat simpleDateFormat= new SimpleDateFormat("yyyyMMdd");
			date = simpleDateFormat.parse(s);
		} catch (ParseException e) {
			logger.error("error={}",e);
		}
		return date;
	}

	/**
	 * date转String
	 * 直流时分秒
	 * @param date
	 * @return
	 */
	public static String UDateToLocalTimeHMS(Date date) {
		Instant instant = date.toInstant();
		ZoneId zone = ZoneId.systemDefault();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
		LocalTime localTime = localDateTime.toLocalTime();
		String format = localTime.format(hhmmss);
		return format;
	}

	/**
	 * 返回一天的结束时间
	 *
	 * @param d
	 * @return
	 */
	public static String getEndTimeOfDays(String d) {
		return d.trim() + " 23:59:59";
	}

	/**
	 * 获取一天最早的时间点 00:00:00
	 *
	 * @param date
	 * @return
	 */
	public static String getEarliestOfDay(String date) {
		return date.trim() + " 00:00:00";
	}

	/**
	 * 获取几个月后的时间
	 * @param d
	 * @param months
	 * @return
	 */
	public static Date addMonth(Date d, int months) {
		if (d == null) {
			return null;
		}
		LocalDateTime localDateTime = UDateToLocalDateTime(d);
		LocalDateTime localDateTime1 = localDateTime.plusMonths(months);
		return localDateTime2Date(localDateTime1);
	}

	/**
	 * 获取对应的localDate
	 * @param date
	 * @return
	 */
	public static LocalDate getLocalDate(Date date) {
		if (null == date) {
			return null;
		}

		return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
	}

	/**
	 * 在localDate上加减月和天
	 * @param date
	 * @param monthsToAdd
	 * @param daysToAdd
	 * @return
	 */
	public static LocalDate addMonthAndDay(Date date, long monthsToAdd, long daysToAdd) {
		if (null == date) {
			return null;
		}

		LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
		localDate = localDate.plusMonths(monthsToAdd);
		localDate = localDate.plusDays(daysToAdd);
		return localDate;
	}

	/**
	 * 在localDate上加减月和天
	 * @param date
	 * @param monthsToAdd
	 * @param daysToAdd
	 * @return
	 */
	public static LocalDate addMonthAndDay(LocalDate date, long monthsToAdd, long daysToAdd) {
		if (null == date) {
			return null;
		}
		// 构造新的
		LocalDate localDate = LocalDate.of(date.getYear(), date.getMonth(),date.getDayOfMonth());
		localDate = localDate.plusMonths(monthsToAdd);
		localDate = localDate.plusDays(daysToAdd);
		return localDate;
	}


	/**
	 * 获得前几小时的时间
	 *
	 * @param d
	 *            需要计算的时间类型
	 * @param hours
	 *            小时数
	 * @return
	 */
	public static Date beforeHours(Date d, int hours) {
		if (d == null) {
			return null;
		}
		LocalDateTime localDateTime = UDateToLocalDateTime(d);
		LocalDateTime localDateTime1 = localDateTime.minusHours(hours);
		return localDateTime2Date(localDateTime1);
	}

	public static String formatDate(Date date, String format) {
		String newDate = "";
		if (date == null){
			return newDate;
		}
		try {
			SimpleDateFormat df = new SimpleDateFormat(format);
			newDate = df.format(date);
		} catch (Exception e) {
			return null;
		}
		return newDate;
	}

	public static String formatDate(Date date, SimpleDateFormat df) {
		String newDate = "";
		if (date == null){
			return newDate;
		}
		try {
			newDate = df.format(date);
		} catch (Exception e) {
			return null;
		}
		return newDate;
	}

	/**
	 * 获取一天最早的时间点 00:00:00
	 *
	 * @param date
	 * @return
	 */
	public static Date getEarliestOfDay(Date date) {
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
		LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
		return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
	}


	/**
	 * 获取一天最晚的时间点 23:59:59
	 *
	 * @param date
	 * @return
	 */
	public static Date getLatestOfDay(Date date) {
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());;
		LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
		return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());

	}

	public static void main(String[] args) {
		System.out.println(addMonth(new Date(),1));
	}

	public static Date format(Date date,String format){
		long time = date.getTime();
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(time);
		SimpleDateFormat df = new SimpleDateFormat(format);
		String newDate = df.format(calendar.getTime());
		Date dateNow = null;
		try {
			dateNow = df.parse(newDate);
		} catch (ParseException e) {
			logger.error("dateNow={}",e);
		}
		return dateNow;
	}

	public static Long getTime(String date, SimpleDateFormat sdf) {
		try {
			return sdf.parse(date).getTime() / 1000;
		} catch (ParseException e) {
			logger.error("getTime={}",e);
		}
		return null;
	}

	/**
	 * 根据两个日期求相差天数
	 * @author:zhuhongqiang
	 * @param smdate
	 * @param bdate
	 * @return
	 */
	public static int daysBetween(Date smdate,Date bdate){
		if (smdate==null || bdate==null){
			return 0;
		}else{
			long between_days=0;
			LocalDateTime localDateTime = UDateToLocalDateTime(smdate);
			LocalDateTime localDateTime1 = UDateToLocalDateTime(bdate);
			smdate = localDateTime2Date(localDateTime);
			bdate = localDateTime2Date(localDateTime1);
			Calendar cal = Calendar.getInstance();
			cal.setTime(smdate);
			long time1 = cal.getTimeInMillis();
			cal.setTime(bdate);
			long time2 = cal.getTimeInMillis();
			between_days = (time2 - time1) / (1000 * 3600 * 24);
			return Integer.parseInt(String.valueOf(between_days));
		}
	}

	/**
	 *	java.util.Date --> java.time.LocalDateTime
 	 */
	public static LocalDateTime UDateToLocalDateTime(Date date) {
		Instant instant = date.toInstant();
		ZoneId zone = ZoneId.systemDefault();
		LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
		return  localDateTime;
	}

	/**
	 * 年月日时分秒
	 * @param date
	 * @return
	 */
	public static Date date2DateByJDK8(Date date){
		LocalDateTime localDateTime = UDateToLocalDateTime(date);
		Date smdate = localDateTime2Date(localDateTime);
		return smdate;
	}

    /**
     * 求时间差秒
     * @param endDate
     * @param nowDate
     * @return
     */
    public static long getDatePoorSeconds(Date endDate, Date nowDate) {
        long interval = (nowDate.getTime() - endDate.getTime())/1000;
        return interval;
    }
	/**
	 * string 转 date 年月日时分秒
	 * @param dateTime
	 * @return
	 */
	public static Date formatterShortDateTime(String dateTime) {
		LocalDateTime localDateTime = LocalDateTime.parse(dateTime, YYYYMMDDHHMMSS);
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = localDateTime.atZone(zone).toInstant();
		return Date.from(instant);
	}
    /**
     * 时间转String
     * @param
     * @return
     */
	public static String dateToStringYYYYMMDDByJDK8(Date date) {
        LocalDateTime localDateTime = dateConvertToLocalDateTime(date);
        String dateTime = localDateTime.format(YYYYMMDD);
        return dateTime;
	}

	/**
	 * date转String yyyyMMdd
	 * @param date
	 * @return
	 */
	public static String dateToStringymdByJDK8(Date date) {
        LocalDateTime localDateTime = dateConvertToLocalDateTime(date);
        String dateTime = localDateTime.format(ymd);
        return dateTime;
	}
    public static String dateToStringYYYYMMDDHHMMSSByJDK8(Date date) {
        LocalDateTime localDateTime = dateConvertToLocalDateTime(date);
        String dateTime = localDateTime.format(YYYYMMDDHHMMSS);
        return dateTime;
    }
    public static String date2StringByJdk8(Date date,DateTimeFormatter dateTimeFormatter) {
		LocalDateTime localDateTime = dateConvertToLocalDateTime(date);
		String dateTime = localDateTime.format(dateTimeFormatter);
		return dateTime;
	}
	/**
	 * 将java.util.Date 转换为java8 的java.time.LocalDateTime,默认时区为东8区
	 * @param date
	 * @return
	 */
	public static LocalDateTime dateConvertToLocalDateTime(Date date) {
		return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
	}

	/**
	 * 将短时间格式时间转换为字符串 yyyy-MM-dd
	 *
	 * @param dateDate
	 * @return
	 */
	public static String dateToStr(Date dateDate) {
        String dateString = dateToStringYYYYMMDDByJDK8(dateDate);
		return dateString;
	}

	/**
	 * 将时分 -> 年月日 时分秒
	 * @param s
	 * @return
	 */
	public static Date stringDateToHHMM(String s) {
		Date date = null;
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
			date = simpleDateFormat.parse(s);
		} catch (ParseException var3) {
		}
		return date;
	}
	public static String dateToHHMMStr(Date date) {
		if (date != null) {
			SimpleDateFormat shortsdf = new SimpleDateFormat("HH:mm");
			return shortsdf.format(date);
		} else {
			return null;
		}
	}
	public static Date stringDateToHHMMSS(String s) {
		Date date = null;
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
			date = simpleDateFormat.parse(s);
		} catch (ParseException var3) {
		}
		return date;
	}
	/**
	 * 将短时间格式字符串转换为时间 yyyy-MM-dd
	 *
	 * @param strDate
	 * @return
	 */
	public static Date strToDate(String strDate) {
	    if (StringUtils.isNotBlank(strDate)){
	        if (strDate.length()<19){
                strDate = (strDate.substring(0,10)+" 00:00:00");
            }
            Date date = formatterShortDateTime(strDate);
	        return date;
        }
        return null;
	}

	/**
	 * 获取当前时间的后n天 时间
	 * @param date1
	 * @return
	 */
	public static Date getNextDayTime(String date1,int day){
		if (StringUtils.isBlank(date1)){
			return null;
		}
		if (StringUtils.isNotBlank(date1)&&date1.length()<=10){
            date1 = date1+" 00:00:00";
        }
        Date date = formatterShortDateTime(date1);
        Date nextDayTime = getNextDayTime(date, day);
        return nextDayTime;
	}

	/**
	 * 获取当前时间的后n天 时间
	 * @param date
	 * @return
	 */
	public static Date getNextDayTime(Date date,int day){
		try {
            LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
            String format = localDateTime.plusDays(day).format(YYYYMMDDHHMMSS);
            Date date1 = formatterShortDateTime(format);
            return date1;
		} catch (Exception e) {
			logger.error("getNextDayTime={}",e);
		}
		return null;
	}

	/**
	 * 获取当前时间的后N秒 时间
	 * @param date
	 * @return
	 */
	public static Date getNextDayTimeBySeconds(Date date,int seconds){
		if (date==null){
			return null;
		}
		try {
			LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
			String format = localDateTime.plusSeconds(seconds).format(YYYYMMDDHHMMSS);
			Date date1 = formatterShortDateTime(format);
			return date1;
		} catch (Exception e) {
			logger.error("getNextDayTimeBySeconds={}",e);
		}
		return null;
	}

	/**
	 * 相差s数
	 * @param start
	 * @param end
	 * @return
	 */
	public static long diffSeconds(Date start, Date end) {
		long diffSec = 0;
		if (start != null && end !=null) {
			diffSec = (end.getTime() - start.getTime()) /1000;
		}else{
			diffSec = 0;
		}
		return diffSec;
	}
	/**
	 * 根据开始结束时间返回这短时间的所有时间
	 * @param start
	 * @param end
	 * @return
	 */
	public static Set<String> getAllByYMD(String start,String end){
        Date strToDateStart = strToDate(start);
        Date strToDateEnd = strToDate(end);
        logger.info("strToDateStart={},,strToDateEnd={},,start888={}",strToDateStart,strToDateEnd,start);
        Integer days = daysBetween(strToDateStart,strToDateEnd);
		Set<String> set = new TreeSet<String>();
		if (days ==null || days==0){
            Date date = strToDate(start);
            String s = dateToStringYYYYMMDDByJDK8(date);
            logger.info("start000={}",s);
			set.add(s);
			return set;
		}
		if (StringUtils.isNotBlank(start) && StringUtils.isNotBlank(end)){
			Date date = strToDate(start);
			Date date1 = strToDate(end);
			if (date!=null && date.equals(date1)){
				set.add(start);
				return set;
			}
		}
		for(int i=0;i<=days;i++){
			Date time = getNextDayTime(start,i);
            String s = dateToStr(time);
            logger.info("s001={},,startDF={},,time001={}",s,start,time);
            set.add(s);
		}
		return set;
	}

	// 获得某天最大时间 2017-10-15 23:59:59
	public static Date getEndOfDay(Date date) {
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
		LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
		return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
	}

	/**
	 * 返回 所需要的的时间节点
	 * @param start
	 * @param end
	 * @return
	 */
	public static List<Date> getAllByYMDList(Date start,Date end) {
		List<Date> list = new ArrayList();
		try {
			Integer days = daysBetween(start,end);
			list.add(start);
			list.add(getEndOfDay(start));
			for(int i=1;i<days;i++){
				Date time = getNextDayTime(start,i);
				Date nextDay = getEndOfDay(time);
				list.add(nextDay);
			}
			list.add(end);
		}catch (Exception e){
			logger.error("getAllByYMDList={}",e);
		}
		return list;
	}

	/**
	 * 看两个日期是否有交集
	 * A时间段,B时间段
	 * 时间格式:yyyy-MM-dd HH:MM
	 *     false 无交集
	 *     true true
	 */
	public static boolean isOverlap(String startA, String endA, String startB, String endB,String sdf) {
		if (StringUtils.isNotBlank(startA) && StringUtils.isNotBlank(endA) && StringUtils.isNotBlank(startB) && StringUtils.isNotBlank(endB)) {
			try {
				Date leftStartDate = stringToLocalDateTime(startA, sdf);
				Date leftEndDate = stringToLocalDateTime(endA, sdf);
				Date rightStartDate = stringToLocalDateTime(startB, sdf);
				Date rightEndDate = stringToLocalDateTime(endB, sdf);
				if (leftStartDate != null && leftEndDate != null && rightStartDate != null && rightEndDate != null) {
					long leftStartDateTime = leftStartDate.getTime();
					long leftEndDateTime = leftEndDate.getTime();
					long rightStartDateTime = rightStartDate.getTime();
					long rightEndDateTime = rightEndDate.getTime();

					return ((leftStartDateTime >= rightStartDateTime)
									&& leftStartDateTime < rightEndDateTime)
									||
									((leftStartDateTime > rightStartDateTime)
											&& leftStartDateTime <= rightEndDateTime)
									||
									((rightStartDateTime >= leftStartDateTime)
											&& rightStartDateTime < leftEndDateTime)
									||
									((rightStartDateTime > leftStartDateTime)
											&& rightStartDateTime <= leftEndDateTime);
				} else {
					return Boolean.FALSE;
				}
			} catch (Exception e) {
				return Boolean.FALSE;
			}
		} else {
			return Boolean.FALSE;
		}
	}


    /**
     * string 转 LocalDateTime
     *
     * @param dateStr 例："2017-08-11 01:00:00"
     * @param format  例："yyyy-MM-dd HH:mm:ss"
     * @return
     */
    public static Date stringToLocalDateTime(String dateStr, String format) {
        try {
            if (StringUtils.isNotBlank(format) && format.length()>0){
                dateStr = dateStr.substring(0,format.length());
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
            LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter);
            return localDateTime2Date(localDateTime);
        } catch (DateTimeParseException e) {
            logger.error("stringToLocalDateTime={}",dateStr,e);
        }
        return null;
    }

    /**
     * LocalDateTime转换为Date
     * @param localDateTime
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime){
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);//Combines this date-time with a time-zone to create a  ZonedDateTime.
        return Date.from(zdt.toInstant());
    }

	/**
	 * 获取本月有多少天
	 *
	 * @param year
	 * @param month
	 * @return
	 */
	public static int getDayOfMonth(String year,String month) {
		Calendar c = Calendar.getInstance();
		c.set(Integer.parseInt(year), Integer.parseInt(month), 0); //输入类型为int类型
		int dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
		return dayOfMonth;
	}

	public static Date getLastMonthStart() {
		return Date.from(LocalDateTime.of(LocalDate.now().plusMonths(-1),
				LocalTime.of(0, 0, 0)).atZone(ZoneId.systemDefault()).toInstant());
	}
	public static Date getLastMonthEnd() {
		return Date.from(LocalDateTime.of(LocalDate.now().plusDays(-1),
				LocalTime.of(23, 59, 59)).atZone(ZoneId.systemDefault()).toInstant());
	}
}
